/**
 * 
 */
package edu.umd.clip.lm.model.data;

import java.io.*;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.regex.*;

import edu.umd.clip.lm.factors.*;
import edu.umd.clip.lm.util.GrowingOutputBuffer;
/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class ContextFuturesPair implements Serializable, Externalizable {
	static final long serialVersionUID = 1L;
	private Context context;
	private TupleCountPair[] futures;
	private long totalCount;
	private static final Pattern split1_re = Pattern.compile("\t");
	private static final Pattern split2_re = Pattern.compile(",");
	/**
	 * @param context
	 * @param futures
	 * @param totalCount
	 */
	public ContextFuturesPair(Context context, TupleCountPair[] futures, long totalCount) {
		this.context = context;
		this.futures = futures;
		this.totalCount = totalCount;
	}
	/**
	 * @param context
	 * @param futures
	 */
	public ContextFuturesPair(Context context, TupleCountPair[] futures) {
		this(context, futures, -1);
	}
	
	public ContextFuturesPair(FactorTupleDescription description, String valueString) {
		String parts[] = split1_re.split(valueString);
		assert(parts.length == 2);
		context = new Context(parts[0]);
		String items[] = split2_re.split(parts[1]);
		futures = new TupleCountPair[items.length];
		for(int i=0; i<futures.length; ++i) {
			futures[i] = new TupleCountPair(items[i]);
		}
		computeTotalCount();
	}
	
	public ContextFuturesPair(ObjectInput in) throws IOException, ClassNotFoundException {
		read(in);
	}
	
	public ContextFuturesPair(DataInput in) throws IOException {
		read(in);
	}
	
	public ContextFuturesPair(ByteBuffer buffer) {
		read(buffer);
	}
	
	protected void computeTotalCount() {
		totalCount = 0;
		for(TupleCountPair pair : futures) {
			totalCount += pair.count;
		}
	}
	
	/**
	 * @return the context
	 */
	public Context getContext() {
		return context;
	}
	/**
	 * @return the futures
	 */
	public TupleCountPair[] getFutures() {
		return futures;
	}
	
	public void setFutures(TupleCountPair[] futures) {
		this.futures = futures;
		this.totalCount = -1;
	}

	/**
	 * @return the totalCount
	 */
	public long getTotalCount() {
		if (totalCount == -1) {
			computeTotalCount();
		}
		return totalCount;
	}
	
	public String toValueString() {
		StringBuilder sb = new StringBuilder(context.toValueString());
		sb.append('\t');
		sb.append(futures[0].toValueString());
		for(int i=1; i<futures.length; ++i) {
			sb.append(',');
			sb.append(futures[i].toValueString());
		}
		return sb.toString();
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(context.toString());
		sb.append('\t');
		sb.append(futures[0].toString());
		for(int i=1; i<futures.length; ++i) {
			sb.append(',');
			sb.append(futures[i].toString());
		}
		return sb.toString();
	}
	
	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		read(in);
	}
	
	public void read(DataInput in) throws IOException {
		context = new Context(in);
		int numFutures = in.readInt();
		futures = new TupleCountPair[numFutures];
		for(int i=0; i<numFutures; ++i) {
			futures[i] = new TupleCountPair(in);
		}
		computeTotalCount();
	}
	
	public void read(ByteBuffer buffer) {
		context = new Context(buffer);
		int numFutures = buffer.getInt();
		futures = new TupleCountPair[numFutures];
		for(int i=0; i<numFutures; ++i) {
			futures[i] = new TupleCountPair(buffer);
		}
		computeTotalCount();		
	}
	
	public void writeExternal(ObjectOutput out) throws IOException {
		write(out);
	}
	public void write(DataOutput out) throws IOException {
		context.write(out);
		out.writeInt(futures.length);
		for(TupleCountPair tc : futures) {
			tc.write(out);
		}
	}
	
	public void write(GrowingOutputBuffer buffer) {
		context.write(buffer);
		buffer.putInt(futures.length);
		for(TupleCountPair tc : futures) {
			tc.write(buffer);
		}
	}
}
